﻿namespace Lilium.CSharp.Expressions

// Active patterns for matching C# expressions.
module Patterns =
    
    open System
    open System.Linq.Expressions

    let (|Add|_|) (expression: Expression) =
        match expression.NodeType with
        | ExpressionType.Add 
            ->  let add = expression :?> BinaryExpression
                Some (add.Left, add.Right)
        | _ ->  None

    let (|Call|_|) (expression: Expression) =
        match expression.NodeType with
        | ExpressionType.Call 
            ->  let call = expression :?> MethodCallExpression 
                Some (call.Method, call.Object, call.Arguments |> List.ofSeq)
        | _ ->  None

    let (|Constant|_|) (expression: Expression) =
        match expression.NodeType with 
        | ExpressionType.Constant 
            ->  let constant = expression :?> ConstantExpression
                Some (constant.Value, constant.Type)
        | _ ->  None

    let (|Convert|_|) (expression: Expression) =
        match expression.NodeType with 
        | ExpressionType.Convert 
            ->  let convert = expression :?> UnaryExpression
                Some (convert.Operand, convert.Type)
        | _ ->  None

    let (|Invoke|_|) (expression: Expression) =
        match expression.NodeType with
        | ExpressionType.Invoke
            ->  let invoke = expression :?> InvocationExpression
                Some (invoke.Expression, invoke.Arguments |> List.ofSeq)
        | _ ->  None

    let (|Lambda|_|) (expression: Expression) =
        match expression.NodeType with
        | ExpressionType.Lambda 
            ->  let lambda = expression :?> LambdaExpression
                Some (lambda.Body, lambda.Parameters |> List.ofSeq)
        | _ ->  None

    let (|MemberAccess|_|) (expression: Expression) =
        match expression.NodeType with 
        | ExpressionType.MemberAccess
            ->  let memberAccess = expression :?> MemberExpression
                Some (memberAccess.Member, memberAccess.Expression)
        | _ ->  None

    let (|Parameter|_|) (expression: Expression) =
        match expression.NodeType with
        | ExpressionType.Parameter 
            ->  let parameter = expression :?> ParameterExpression
                Some (parameter.Name, parameter.Type)
        | _ ->  None